rcar_gen3: drivers: watchdog
authorJorge Ramirez-Ortiz <[email protected]>
Sun, 23 Sep 2018 07:42:08 +0000 (09:42 +0200)
committerldts <[email protected]>
Wed, 17 Oct 2018 16:42:31 +0000 (18:42 +0200)
Signed-off-by: ldts <[email protected]>
drivers/renesas/rcar/watchdog/swdt.c [new file with mode: 0644]

diff --git a/drivers/renesas/rcar/watchdog/swdt.c b/drivers/renesas/rcar/watchdog/swdt.c
new file mode 100644 (file)
index 0000000..6df47b9
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <gicv2.h>
+#include <mmio.h>
+#include "rcar_def.h"
+
+extern void gicd_set_icenabler(uintptr_t base, unsigned int id);
+
+#define RST_BASE                       (0xE6160000U)
+#define RST_WDTRSTCR                   (RST_BASE + 0x0054U)
+#define SWDT_BASE                      (0xE6030000U)
+#define SWDT_WTCNT                     (SWDT_BASE + 0x0000U)
+#define SWDT_WTCSRA                    (SWDT_BASE + 0x0004U)
+#define SWDT_WTCSRB                    (SWDT_BASE + 0x0008U)
+#define SWDT_GICD_BASE                 (0xF1010000U)
+#define SWDT_GICC_BASE                 (0xF1020000U)
+#define SWDT_GICD_CTLR                 (SWDT_GICD_BASE + 0x0000U)
+#define SWDT_GICD_IGROUPR              (SWDT_GICD_BASE + 0x0080U)
+#define SWDT_GICD_ISPRIORITYR          (SWDT_GICD_BASE + 0x0400U)
+#define SWDT_GICC_CTLR                 (SWDT_GICC_BASE + 0x0000U)
+#define SWDT_GICC_PMR                  (SWDT_GICC_BASE + 0x0004U)
+#define SWDT_GICD_ITARGETSR            (SWDT_GICD_BASE + 0x0800U)
+#define IGROUPR_NUM                    (16U)
+#define ISPRIORITY_NUM                 (128U)
+#define ITARGET_MASK                   (0x03U)
+
+#define WDTRSTCR_UPPER_BYTE            (0xA55A0000U)
+#define WTCSRA_UPPER_BYTE              (0xA5A5A500U)
+#define WTCSRB_UPPER_BYTE              (0xA5A5A500U)
+#define WTCNT_UPPER_BYTE               (0x5A5A0000U)
+#define WTCNT_RESET_VALUE              (0xF488U)
+#define WTCSRA_BIT_CKS                 (0x0007U)
+#define WTCSRB_BIT_CKS                 (0x003FU)
+#define SWDT_RSTMSK                    (1U << 1U)
+#define WTCSRA_WOVFE                   (1U << 3U)
+#define WTCSRA_WRFLG                   (1U << 5U)
+#define SWDT_ENABLE                    (1U << 7U)
+
+#define WDTRSTCR_MASK_ALL              (0x0000FFFFU)
+#define WTCSRA_MASK_ALL                        (0x000000FFU)
+#define WTCNT_INIT_DATA                        (WTCNT_UPPER_BYTE + WTCNT_RESET_VALUE)
+#define WTCSRA_INIT_DATA               (WTCSRA_UPPER_BYTE + 0x0FU)
+#define WTCSRB_INIT_DATA               (WTCSRB_UPPER_BYTE + 0x21U)
+
+#define WTCNT_COUNT_8p13k              (0x10000U - 40687U)
+#define WTCNT_COUNT_8p13k_H3VER10      (0x10000U - 20343U)
+#define WTCNT_COUNT_8p22k              (0x10000U - 41115U)
+#define WTCNT_COUNT_7p81k              (0x10000U - 39062U)
+#define WTCSRA_CKS_DIV16               (0x00000002U)
+
+static void swdt_disable(void)
+{
+       uint32_t rmsk;
+
+       rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL;
+       rmsk |= SWDT_RSTMSK;
+       mmio_write_32(RST_WDTRSTCR, WDTRSTCR_UPPER_BYTE | rmsk);
+
+       mmio_write_32(SWDT_WTCNT, WTCNT_INIT_DATA);
+       mmio_write_32(SWDT_WTCSRA, WTCSRA_INIT_DATA);
+       mmio_write_32(SWDT_WTCSRB, WTCSRB_INIT_DATA);
+
+       /* Set the interrupt clear enable register */
+       gicd_set_icenabler(RCAR_GICD_BASE, ARM_IRQ_SEC_WDT);
+}
+
+void rcar_swdt_init(void)
+{
+       uint32_t rmsk, val, sr;
+#if (RCAR_LSI != RCAR_E3)
+       uint32_t reg, product_cut, chk_data;
+
+       reg = mmio_read_32(RCAR_PRR);
+       product_cut = reg & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+
+       reg = mmio_read_32(RCAR_MODEMR);
+       chk_data = reg & CHECK_MD13_MD14;
+#endif
+       /* stop watchdog */
+       if (mmio_read_32(SWDT_WTCSRA) & SWDT_ENABLE)
+               mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE);
+
+       mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE |
+                     WTCSRA_WOVFE | WTCSRA_CKS_DIV16);
+
+#if (RCAR_LSI == RCAR_E3)
+       mmio_write_32(SWDT_WTCNT, WTCNT_UPPER_BYTE | WTCNT_COUNT_7p81k);
+#else
+       val = WTCNT_UPPER_BYTE;
+
+       switch (chk_data) {
+       case MD14_MD13_TYPE_0:
+       case MD14_MD13_TYPE_2:
+               val |= WTCNT_COUNT_8p13k;
+               break;
+       case MD14_MD13_TYPE_1:
+               val |= WTCNT_COUNT_8p22k;
+               break;
+       case MD14_MD13_TYPE_3:
+               val |= product_cut == (RCAR_PRODUCT_H3 | RCAR_CUT_VER10) ?
+                   WTCNT_COUNT_8p13k_H3VER10 : WTCNT_COUNT_8p13k;
+               break;
+       default:
+               ERROR("MODEMR ERROR value = %x\n", chk_data);
+               panic();
+               break;
+       }
+
+       mmio_write_32(SWDT_WTCNT, val);
+#endif
+       rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL;
+       rmsk |= SWDT_RSTMSK | WDTRSTCR_UPPER_BYTE;
+       mmio_write_32(RST_WDTRSTCR, rmsk);
+
+       while ((mmio_read_8(SWDT_WTCSRA) & WTCSRA_WRFLG) != 0U)
+               ;
+
+       /* Start the System WatchDog Timer */
+       sr = mmio_read_32(SWDT_WTCSRA) & WTCSRA_MASK_ALL;
+       mmio_write_32(SWDT_WTCSRA, (WTCSRA_UPPER_BYTE | sr | SWDT_ENABLE));
+}
+
+void rcar_swdt_release(void)
+{
+       uintptr_t itarget = SWDT_GICD_ITARGETSR +
+           (ARM_IRQ_SEC_WDT & ~ITARGET_MASK);
+       uint32_t i;
+
+       write_daifset(DAIF_FIQ_BIT);
+       swdt_disable();
+       gicv2_cpuif_disable();
+
+       for (i = 0; i < IGROUPR_NUM; i++)
+               mmio_write_32(SWDT_GICD_IGROUPR + i * 4, 0U);
+
+       for (i = 0; i < ISPRIORITY_NUM; i++)
+               mmio_write_32(SWDT_GICD_ISPRIORITYR + i * 4, 0U);
+
+       mmio_write_32(itarget, 0U);
+       mmio_write_32(SWDT_GICD_CTLR, 0U);
+       mmio_write_32(SWDT_GICC_CTLR, 0U);
+       mmio_write_32(SWDT_GICC_PMR, 0U);
+}
+
+void rcar_swdt_exec(uint64_t p)
+{
+       gicv2_end_of_interrupt(ARM_IRQ_SEC_WDT);
+       rcar_swdt_release();
+       ERROR("\n");
+       ERROR("System WDT overflow, occured address is %p\n", (void *)p);
+       panic();
+}